package main

import (
	"embed"
	"log"
	"os"
	"path/filepath"
	"syscall"
	"time"
	"unsafe"

	webview2 "github.com/jchv/go-webview2"
)

var (
	Version   = "1.0.0"
	BuildTime = "unknown"
	GoVersion = "unknown"
)

//go:embed web/*
var assets embed.FS

//go:embed icon.ico
var iconData []byte

func main() {
	// 创建应用数据目录
	if err := createAppDataDir(); err != nil {
		log.Fatal("创建应用数据目录失败:", err)
	}

	// 启动HTTP服务器
	server := NewServer(assets)
	go server.Start()

	// 创建WebView2窗口
	w := webview2.NewWithOptions(webview2.WebViewOptions{
		Debug:     false,
		AutoFocus: true,
		WindowOptions: webview2.WindowOptions{
			Title:  "Hermes",
			Width:  1200,
			Height: 800,
			// 不设置IconId，让程序动态设置图标
		},
	})
	defer w.Destroy()

	// 绑定Go函数到JavaScript
	w.Bind("sendRequest", server.SendRequest)
	w.Bind("saveTab", server.SaveTab)
	w.Bind("loadTab", server.LoadTab)
	w.Bind("getUrlHistory", server.GetUrlHistory)
	w.Bind("saveSettings", server.SaveSettings)
	w.Bind("loadSettings", server.LoadSettings)
	w.Bind("generateSignature", server.GenerateSignature)
	w.Bind("encryptSM4", server.EncryptSM4)
	w.Bind("decryptSM4", server.DecryptSM4)
	w.Bind("getEnvironmentConfig", server.GetEnvironmentConfig)
	w.Bind("saveEnvironmentConfig", server.SaveEnvironmentConfig)

	// 导航到本地服务器
	w.Navigate("http://localhost:8080")

	// 设置窗口图标
	go func() {
		// 等待窗口完全加载
		time.Sleep(500 * time.Millisecond)
		
		// 创建临时图标文件
		iconPath, err := createTempIcon()
		if err != nil {
			log.Printf("创建图标文件失败: %v", err)
			return
		}
		
		if iconPath == "" {
			log.Printf("图标路径为空，跳过图标设置")
			return
		}

		// 尝试设置图标，最多重试20次
		for i := 0; i < 20; i++ {
			if setWindowIcon(iconPath) {
				break
			}
			// 等待100毫秒后重试
			time.Sleep(100 * time.Millisecond)
		}
	}()

	w.Run()
}

func createAppDataDir() error {
	appDataDir, err := getAppDataDir()
	if err != nil {
		return err
	}

	dirs := []string{
		appDataDir,
		filepath.Join(appDataDir, "tabs"),
		filepath.Join(appDataDir, "settings"),
	}

	for _, dir := range dirs {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return err
		}
	}

	return nil
}

func getAppDataDir() (string, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(homeDir, "AppData", "Local", "Hermes"), nil
}

func createTempIcon() (string, error) {
	// 首先尝试使用当前目录的图标文件
	currentDir, err := os.Getwd()
	if err == nil {
		iconPath := filepath.Join(currentDir, "icon.ico")
		if _, err := os.Stat(iconPath); err == nil {
			return iconPath, nil
		}
	}

	// 如果当前目录没有图标文件，创建临时图标文件
	tempDir := os.TempDir()
	iconPath := filepath.Join(tempDir, "hermes_icon.ico")

	// 检查临时图标文件是否已存在且有效
	if stat, err := os.Stat(iconPath); err == nil && stat.Size() > 0 {
		return iconPath, nil
	}

	// 确保嵌入的图标数据不为空
	if len(iconData) == 0 {
		log.Printf("嵌入的图标数据为空")
		return "", nil // 返回空路径，让系统使用默认图标
	}

	// 写入图标数据到临时文件
	err = os.WriteFile(iconPath, iconData, 0644)
	if err != nil {
		log.Printf("写入临时图标文件失败: %v", err)
		return "", err
	}

	log.Printf("图标文件已创建: %s (大小: %d 字节)", iconPath, len(iconData))
	return iconPath, nil
}

// Windows API 函数声明
var (
	user32                       = syscall.NewLazyDLL("user32.dll")
	kernel32                     = syscall.NewLazyDLL("kernel32.dll")
	procFindWindowW              = user32.NewProc("FindWindowW")
	procEnumWindows              = user32.NewProc("EnumWindows")
	procGetWindowTextW           = user32.NewProc("GetWindowTextW")
	procGetWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
	procSetClassLongW            = user32.NewProc("SetClassLongW")
	procSetClassLongPtrW         *syscall.LazyProc
	procLoadImageW               = user32.NewProc("LoadImageW")
	procSendMessageW             = user32.NewProc("SendMessageW")
	procGetCurrentProcessId      = kernel32.NewProc("GetCurrentProcessId")
)

func init() {
	// 尝试加载64位版本的SetClassLongPtrW，如果失败则使用32位版本的SetClassLongW
	if err := user32.NewProc("SetClassLongPtrW").Find(); err == nil {
		procSetClassLongPtrW = user32.NewProc("SetClassLongPtrW")
	} else {
		procSetClassLongPtrW = procSetClassLongW
	}
}

const (
	GCL_HICON       = uintptr(^uintptr(14 - 1)) // -14
	GCL_HICONSM     = uintptr(^uintptr(34 - 1)) // -34
	IMAGE_ICON      = 1
	LR_LOADFROMFILE = 0x00000010
	WM_SETICON      = 0x0080
	ICON_BIG        = 1
	ICON_SMALL      = 0
)

func setWindowIcon(iconPath string) bool {
	// 获取当前进程ID
	currentPID, _, _ := procGetCurrentProcessId.Call()

	// 查找属于当前进程的窗口
	hwnd := findWindowByProcess(uint32(currentPID))

	if hwnd == 0 {
		// log.Printf("未找到窗口句柄")
		return false
	}

	// 检查图标文件是否存在
	if _, err := os.Stat(iconPath); os.IsNotExist(err) {
		log.Printf("图标文件不存在: %s", iconPath)
		return false
	}

	// 加载图标文件
	iconPathPtr, _ := syscall.UTF16PtrFromString(iconPath)

	// 加载大图标 (32x32)
	hIconLarge, _, err := procLoadImageW.Call(
		0,
		uintptr(unsafe.Pointer(iconPathPtr)),
		IMAGE_ICON,
		32,
		32,
		LR_LOADFROMFILE,
	)

	// 加载小图标 (16x16)
	hIconSmall, _, _ := procLoadImageW.Call(
		0,
		uintptr(unsafe.Pointer(iconPathPtr)),
		IMAGE_ICON,
		16,
		16,
		LR_LOADFROMFILE,
	)

	if hIconLarge == 0 && hIconSmall == 0 {
		log.Printf("加载图标失败: %v", err)
		return false
	}

	success := false

	// 使用 SendMessage 设置图标（更可靠的方法）
	if hIconLarge != 0 {
		procSendMessageW.Call(hwnd, WM_SETICON, ICON_BIG, hIconLarge)
		success = true
	}

	if hIconSmall != 0 {
		procSendMessageW.Call(hwnd, WM_SETICON, ICON_SMALL, hIconSmall)
		success = true
	}

	// 同时尝试设置类图标（用于任务栏）
	if procSetClassLongPtrW != nil {
		if hIconLarge != 0 {
			procSetClassLongPtrW.Call(hwnd, uintptr(GCL_HICON), hIconLarge)
		}
		if hIconSmall != 0 {
			procSetClassLongPtrW.Call(hwnd, uintptr(GCL_HICONSM), hIconSmall)
		}
	}

	return success
}

// 查找属于指定进程的窗口
func findWindowByProcess(targetPID uint32) uintptr {
	var foundHwnd uintptr

	// 枚举所有顶级窗口
	enumProc := syscall.NewCallback(func(hwnd uintptr, lParam uintptr) uintptr {
		var pid uint32
		procGetWindowThreadProcessId.Call(hwnd, uintptr(unsafe.Pointer(&pid)))

		if pid == targetPID {
			// 获取窗口标题
			var title [256]uint16
			procGetWindowTextW.Call(hwnd, uintptr(unsafe.Pointer(&title[0])), 256)
			titleStr := syscall.UTF16ToString(title[:])

			// 检查是否是我们的窗口
			if titleStr == "Hermes" || titleStr != "" {
				foundHwnd = hwnd
				return 0 // 停止枚举
			}
		}
		return 1 // 继续枚举
	})

	procEnumWindows.Call(enumProc, 0)
	return foundHwnd
}
